﻿using Padsurface.CoreAudio.Common;
using Padsurface.CoreAudio.Components.WASAPI.Interfaces;
using Padsurface.CoreAudio.Constants;
using Padsurface.CoreAudio.Enumerations;
using Padsurface.CoreAudio.MultiMediaStructures;
using Padsurface.CoreAudio.Wrappers.Services.Interfaces;
using System;
using System.Composition;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

namespace Padsurface.CoreAudio.Wrappers.Model
{
    public class AudioStream
    {
        private IAudioStreamState _audioStreamState;

        internal IAudioClientActivator AudioClientActivator { get; private set; }
        internal IAudioCaptureClientActivator AudioCaptureClientActivator { get; private set; }
        internal Guid AudioSessionGuid { get; private set; }

        internal IAudioClient AudioClient { get; set; }
        internal IAudioCaptureClient AudioCaptureClient { get; set; }
        internal IntPtr DeviceFormatPointer { get; set; }
        internal uint BufferSize { get; set; }
        internal bool ContinueCapturing { get; set; }

        public event EventHandler<AudioStreamBufferCapturedEventArgs> AudioStreamBufferCaptured;
        public WaveFormatEx MixFormat { get; internal set; }

        [ImportingConstructor]
        public AudioStream(IAudioClientActivator audioClientActivator, IAudioCaptureClientActivator audioCaptureClientActivator)
        {
            if (audioClientActivator == null) throw new ArgumentNullException("audioClientActivator");
            if (audioCaptureClientActivator == null) throw new ArgumentNullException("audioCaptureClientActivator");

            AudioClientActivator = audioClientActivator;
            AudioCaptureClientActivator = audioCaptureClientActivator;

            AudioSessionGuid = Guid.NewGuid();
            SetState(new AudioStreamUninitializedState());
        }

        internal void SetState(IAudioStreamState state)
        {
            if (state == null) throw new ArgumentNullException("state");

            _audioStreamState = state;
        }

        public Task Initialize()
        {
            return _audioStreamState.Initialize(this);
        }

        public void Start()
        {
            _audioStreamState.Start(this);
        }

        public Task Stop()
        {
            return _audioStreamState.Stop(this);
        }

        public void Dispose()
        {
            if (DeviceFormatPointer != null)
                Marshal.FreeCoTaskMem(DeviceFormatPointer);
        }

        internal void OnAudioStreamBufferCaptured(byte[] data, int dataSize)
        {
            if (AudioStreamBufferCaptured != null)
                AudioStreamBufferCaptured(this, new AudioStreamBufferCapturedEventArgs(data, dataSize));
        }
    }
}